Tiedon lukeminen luotettavasti ja fiksusti etäpalvelimelta WordPressissä

Jos WordPressissä haluaa ladata jotain dataa saitin ulkopuolelta, sehän käy kätevästi wp_remote_get()-funktiolla. Tällaisten kutsujen yhteydessä on aina syytä huolehtia välimuistittamisesta. Ilman välimuistia jokaisella sivunlatauksella kysellään dataa etäpalvelimelta ja siinä törmätään monenlaisiin ongelmiin nopeasti.

Jatkuva kyseleminen tuottaa turhaa tietoliikennettä ja rasittaa etäpalvelinta turhaan. Jos tieto ei ole niin nopeasti muuttuvaa, että sitä on välttämätöntä seurata reaaliajassa, kannattaa suosiolla tallentaa haettu tieto omalle palvelimelle välimuistiin ja käydä sitten aina välillä päivittämässä välimuistin sisältö ajan tasalle.

Yksinkertaisin ratkaisu: transient

WordPress tarjoaa välimuistiin hyvän mekanismin Transients-rajapinnan muodossa. Transientit ovat tilapäisiksi tarkoitettuja avain–arvo-pareja, jotka tallennetaan oletusarvoisesti tietokantaan (wp_options-tauluun) tai mahdollisesti nopeampaan välimuistiin, jos palveluntarjoaja sellaista käyttää.

Kun transient tallennetaan, sille annetaan erääntymisaika ja jos sitä haetaan tietokannasta erääntymisajan kuluttua, tietokanta palauttaa tyhjää, eli on aika hakea uusi tieto.

Niinpä yksinkertaisin tapa tallentaa wp_remote_get():llä haettu data tilapäisesti on laittaa se transientiin ja antaa transientille sopiva erääntymisaika (vinkki: aika annetaan sekunteina ja sitä varten WordPressissä on hyödyllisiä vakioita kuten DAY_IN_SECONDS ja WEEK_IN_SECONDS).

Tuplavarmistus on tarpeen

Tässä lähestymistavassa on kuitenkin pieni ongelma. Joskus voi käydä niin, että transient on erääntynyt, tietoa haetaan uudestaan, mutta palvelin ei syystä tai toisesta vastaakaan. Silloin tuloksena on tyhjentynyt transient, eikä uutta tietoa tilalle.

Asiaan on onneksi helppo ratkaisu: käytetään tuplavarmistusta. Sen lisäksi, että data tallennetaan transientiin, tallennetaan se myös pysyvään asetukseen.

Jos transient on mennyt vanhaksi, haetaan uusi data, mutta jos uutta dataa ei saada, ei hätää: palautetaan pysyvästä asetuksesta sinne varmuuskopioitu data. Sama data voidaan laittaa myös transientiin vaikkapa tunniksi, jotta etäpalvelimelta ei tarvitse kysellä ei-oota liian usein – tunnin välein tarkistaminen riittänee useimmissa tapauksissa.

Valmis funktio

Paketoin tämän toiminnallisuuden funktioksi wp_remote_get_with_cache(). Funktio löytyy myös Gististä. Funktio saa nipun parametrejä:

  • $url on ladattavan sivun URL.
  • $key on tiedon tallentamiseen käytettävän transientin ja asetuksen nimi.
  • $args sisältää wp_remote_get()-funktiolle välitettävät parametrit, oletuksena ei mitään.
  • $expiry on transientin erääntymisaika, oletuksena vuorokausi (DAY_IN_SECONDS).
  • $callback on funktio, joka saa parametrikseen etäpalvelimelta ladatun datan ja jolla aineistoa voi muokata ennen sen tallentamista välimuistiin.

Funktio palauttaa ladatun datan JSON-koodattuna merkkijonona.

/**
 * Fetches remote data with dual-layer caching.
 *
 * Uses wp_remote_get to fetch remote data. The data is cached twice: it's
 * stored in a transient and an option. The transient is used as the main cache
 * but if the transient has expired and the remote site doesn't respond, 
 * backup data from the option is returned.
 *
 * @param string $url      The URL of the remote resource.
 * @param string $key      The name of the option and the transient.
 * @param array  $args     Argument array that is passed on to wp_remote_get().
 * Default empty array.
 * @param int    $expiry   The expiration length of the transient, default
 * DAY_IN_SECONDS.
 * @param string $callback A callback function that is applied to the data
 * before it's saved in the transient and option. Default null.
 *
 * @see wp_remote_get()
 *
 * @return string The remote data set, JSON encoded.
 */
function wp_remote_get_with_cache( $url, $key, $args = array(), $expiry = DAY_IN_SECONDS, $callback = null ) {
	$data = get_transient( $key );
	if ( $data ) {
		// Data found in cache, return that.
		return json_decode( $data );
	}

	$response = wp_remote_get( $url, $args );
	if ( ! is_array( $response ) ) {
		// Couldn't get the remote data, set the transient for an hour to avoid
		// bothering the server and return backup data.
		$json_encoded_data = json_decode( get_option( $key ) );
		set_transient( $key, $json_encoded_data, HOUR_IN_SECONDS );
		return $json_encoded_data;
	}

	$fetched_data = $response['body'];
	if ( is_callable( $callback ) ) {
		$fetched_data = call_user_func( $callback, $fetched_data );
	}

	$json_encoded_data = wp_json_encode( $fetched_data );
	set_transient( $key, $json_encoded_data, $expiry );
	update_option( $key, $json_encoded_data, false );

	return $fetched_data;
}

Autoload (16.4.2020)

Pieni päivitys tähän, että update_option():lle kannattaa antaa kolmanneksi parametriksi false, joka kytkee asetuksen automaattisen latauksen pois päältä. Tämä automaattinen lataus saa asetuksen latautumaan aina jokaisella sivunlatauksella.

Se on tässä tapauksessa turhaa ja haitallista, koska asetusta ei tarvita kuin harvoin. Niinpä autoload kannattaa suosiolla kytkeä pois päältä, jotta asetusta ei ladata turhaan silloin kun sitä ei tarvita.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

This site uses Akismet to reduce spam. Learn how your comment data is processed.